﻿using System;
using Snake.Logger;

namespace Snake.Gameplay
{
    [Serializable]
    public sealed class GameplayEffectModifier
    {
        public string attribute;

        /// <summary>
        /// 修改方式
        /// </summary>
        public ModifierOp modifierOp;

        /// <summary>
        /// 大小
        /// </summary>
        public float magnitude;

        public bool CanApply(GameplayAttributeSet set)
        {
            var data = set[attribute];
            if (data == null)
            {
                Log.Warn("Attribute is invalid.");
                return false;
            }

            if (magnitude < 0f)
            {
                throw new NotSupportedException("Magnitude must > 0");
            }

            return modifierOp switch
            {
                ModifierOp.Add => true,
                ModifierOp.Subtract => magnitude > data.Value,
                ModifierOp.Multiply => true,
                ModifierOp.Divide => true,
                ModifierOp.Override => true,
                ModifierOp.Invalid => true,
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        public void ApplyInstantAndPeriodic(GameplayAttributeSet set)
        {
            var attributeData = set[attribute];
            if (attributeData == null)
            {
                Log.Warn("Attribute is invalid.");
                return;
            }

            if (magnitude < 0f)
            {
                throw new NotSupportedException("Magnitude must > 0");
            }

            Apply(attributeData);
        }

        public void ApplyDurationAndInfinite(GameplayAttributeSet set)
        {
            var attributeData = set[attribute];
            if (attributeData == null)
            {
                Log.Warn("Attribute is invalid.");
                return;
            }

            if (magnitude < 0f)
            {
                throw new NotSupportedException("Magnitude must > 0");
            }

            attributeData.AddModifier(this);
        }

        public void ResetDurationAndInfinite(GameplayAttributeSet set)
        {
            var attributeData = set[attribute];
            if (attributeData == null)
            {
                Log.Warn("Attribute is invalid.");
                return;
            }

            if (magnitude < 0f)
            {
                throw new NotSupportedException("Magnitude must > 0");
            }

            attributeData.RemoveModifier(this);
        }

        /// <summary>
        /// 计算临时变化
        /// </summary>
        /// <param name="attributeData"></param>
        public void Calculate(GameplayAttributeData attributeData)
        {
            switch (modifierOp)
            {
                case ModifierOp.Add:
                {
                    attributeData.CurrentValue += magnitude;
                    break;
                }
                case ModifierOp.Subtract:
                {
                    attributeData.CurrentValue -= magnitude;
                    break;
                }
                case ModifierOp.Multiply:
                {
                    attributeData.CurrentValue *= magnitude;
                    break;
                }
                case ModifierOp.Divide:
                {
                    attributeData.CurrentValue /= magnitude;
                    break;
                }
                case ModifierOp.Override:
                {
                    attributeData.CurrentValue = magnitude;
                    break;
                }
                case ModifierOp.Invalid:
                default:
                    break;
            }
        }

        /// <summary>
        /// 应用变化
        /// </summary>
        /// <param name="attributeData"></param>
        private void Apply(GameplayAttributeData attributeData)
        {
            switch (modifierOp)
            {
                case ModifierOp.Add:
                {
                    attributeData.Value += magnitude;
                    break;
                }
                case ModifierOp.Subtract:
                {
                    attributeData.Value -= magnitude;
                    break;
                }
                case ModifierOp.Multiply:
                {
                    attributeData.Value *= magnitude;
                    break;
                }
                case ModifierOp.Divide:
                {
                    attributeData.Value /= magnitude;
                    break;
                }
                case ModifierOp.Override:
                {
                    attributeData.Value = magnitude;
                    break;
                }
                case ModifierOp.Invalid:
                default:
                    break;
            }
        }
    }
}